package com.rybbaby.tss.core.aop;

import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.net.URLDecoder;
import java.sql.Timestamp;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.http.Part;

import com.rybbaby.tss.core.annotation.RequestLog;
import com.rybbaby.tss.core.annotation.Token;
import com.rybbaby.tss.core.aop.db.IPersistenceRequestLog;
import com.rybbaby.tss.core.aop.db.RequestLogBean;
import com.rybbaby.tss.core.redis.RedisClient;
import com.rybbaby.tss.core.utils.*;
import com.rybbaby.tss.core.verifier.AbstractVerifier;
import com.rybbaby.tss.core.web.controller.BaseController;
import net.sf.json.JSONObject;

import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.lang.ClassUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.springframework.web.multipart.support.DefaultMultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;

/**
 * @author 谢进伟
 * @description 记录请求相关日志, 同时对重复提交的请求进行拦截处理
 * @createDate 2016年3月12日 上午10:12:40
 */
@Aspect
public class RequestAOP {

    private Logger logger = Logger.getLogger(RequestAOP.class);
    /**
     * 编码方式
     **/
    private String encoding = "UTF-8";
    /**
     * 当前请求的控制器类
     **/
    private Class<? extends Object> controllerClass;
    /**
     * 持久化请求日志到数据库接口
     **/
    private IPersistenceRequestLog persistenceRequestLog;
    /**
     * 需要验证token的表单中formKey的name属性值
     */
    private static final String formKeyParamName = "formKey";
    /**
     * 需要验证token的表单中formToken的name属性值
     */
    private static final String formTokenParamName = "formToken";
    /**
     * 当前请求处理请求的方法对象
     **/
    private Method method;
    /**
     * 连接点签名对象
     **/
    private Signature signature;
    /**
     * 请求传入的参数
     **/
    private Object[] requestParams;
    /**
     * 是否继续处理请求
     **/
    private boolean isProceed = true;
    /**
     * 当前处理请求方法Token注解
     **/
    private Token token;
    /**
     * 当前处理请求方法日志注解
     **/
    private RequestLog requestLog;
    /**
     * 时候需要将日志持久化到数据库
     **/
    private boolean isPersistenceRequestLog = false;
    /**
     * token后缀
     **/
    private static final String tokenSuffixName = "TempToken";
    /**
     * 当前请求对象
     **/
    @Autowired
    private HttpServletRequest request;
    /**
     * 当前会话对象
     **/
    private HttpSession session;
    /**
     * 当前传入参数格式错误错误信息
     **/
    private StringBuffer reqeustParameterFromatErrorInfo;
    /**
     * 当前传入参数未通过自定义服务器端验证的错误错误信息
     **/
    private StringBuffer reqeustParameterCustomValidateErrorInfo;
    /**
     * 是否记录请求日志
     **/
    private boolean isShowlog = true;
    /**
     * 是否自动验证有验证注解的参数
     **/
    private boolean isAutoValidateParameter = true;
    /**
     * 是否自动验证Token以防止重复提交表单
     **/
    private boolean isAutoValidateToken = false;
    /**
     * 请求参数验证失败的默认视图
     **/
    private String requestValidateFailureDefaultView = "";
    /**
     * 发送异常时跳转的视图
     **/
    private String exceptionView;
    /**
     * 请求处理时间记录临时变量
     **/
    private long startTime, endTime;
    /**
     * 是否为开发模式
     **/
    private Boolean isDevModel = true;

    /**
     * 请求日志对象
     **/
    private RequestLogBean requestLogInfo = new RequestLogBean();

    /**
     * 设置参数编码方式
     *
     * @param encoding 编码方式,默认采用UTF-8
     */
    public void setEncoding(String encoding) {
        this.encoding = encoding;
    }

    /**
     * 是否记录请求日志
     *
     * @param isShowlog 是否记录请求日志
     */
    public void setShowlog(boolean isShowlog) {
        this.isShowlog = isShowlog;
    }

    /**
     * 是否自动验证有验证注解的参数
     *
     * @param isAutoValidateParameter 是否自动验证有验证注解的参数
     */
    public void setAutoValidateParameter(boolean isAutoValidateParameter) {
        this.isAutoValidateParameter = isAutoValidateParameter;
    }

    /**
     * 是否自动验证Token以防止重复提交表单
     *
     * @param isAutoValidateToken 是否自动验证Token以防止重复提交表单
     */
    public void setAutoValidateToken(boolean isAutoValidateToken) {
        this.isAutoValidateToken = isAutoValidateToken;
    }

    /**
     * 请求参数验证失败的默认视图
     *
     * @param requestValidateFailureDefaultView 请求参数验证失败的默认视图
     */
    public void setRequestValidateFailureDefaultView(String requestValidateFailureDefaultView) {
        this.requestValidateFailureDefaultView = requestValidateFailureDefaultView;
    }

    /**
     * 发送异常时跳转的视图
     *
     * @param exceptionView 发送异常时跳转的视图
     */
    public void setExceptionView(String exceptionView) {
        this.exceptionView = exceptionView;
    }

    @Pointcut(value = "(@within(org.springframework.stereotype.Controller) || @within(org.springframework.web.bind.annotation.RestController)) && @annotation(org.springframework.web.bind.annotation.RequestMapping)")
    public void requestPointcut() {
    }

    /**
     * 环绕通知,在即将要进入方法执行时切入,必要时可直接阻止原该有逻辑的执行
     *
     * @param pjp 连接点
     */
    @Around(value = "requestPointcut()")
    public Object doAround(ProceedingJoinPoint pjp) {
        if (isPersistenceRequestLog) {
            requestLogInfo.setRequestTime(new Timestamp(System.currentTimeMillis()));
        }
        log("----------------------------  PROCESSING  BEGIN  ----------------------------------");
        Object result = null;
        try {
            initAopField(pjp);
            if (isProceed) {
                startTime = System.currentTimeMillis();
                result = pjp.proceed();
                if (result != null && !(result instanceof ModelAndView)) {
                    try {
                        JSONObject resultJson = JSONObject.fromObject(result);
                        if (resultJson != null) {
                            Integer resCode = resultJson.getInt("resCode");
                            if (resCode == 500) {
                                throw new Exception(resultJson.getString("resMsg"));
                            }
                        }
                    } catch (Exception e) {
                        throw e;
                    }
                }
            } else {
                AjaxJsonResponse ajr = null;
                if (reqeustParameterFromatErrorInfo != null || reqeustParameterCustomValidateErrorInfo != null) {
                    if (reqeustParameterFromatErrorInfo != null) {
                        result = StringUtils.substringBeforeLast(reqeustParameterFromatErrorInfo.toString(), ",");
                    }
                    if (reqeustParameterCustomValidateErrorInfo != null) {
                        String spar = result == null ? (result = "") + "" : ",";
                        result += spar + StringUtils.substringBeforeLast(reqeustParameterCustomValidateErrorInfo.toString(), ",");
                    }
                    logger.warn("request parameter format error or not verified!");
                    ajr = new AjaxJsonResponse(result + "", 300);
                } else {
                    logger.warn("duplicate submissions, has refused to deal with this request!");
                    reqeustParameterFromatErrorInfo.append("duplicate submissions, has refused to deal with this request!");
                }
                log("validate result info：" + result);
                String message = reqeustParameterFromatErrorInfo.toString();
                boolean isRestController = this.controllerClass.isAnnotationPresent(RestController.class);
                boolean isResponseBodyController = this.controllerClass.isAnnotationPresent(ResponseBody.class);
                boolean isResponseBody = this.method.isAnnotationPresent(ResponseBody.class);
                if (isRestController || isResponseBodyController || isResponseBody) {
                    ajr = new AppResponse(message + "", 500);
                    result = ajr.jsonResponse(false);
                } else {
                    ajr = new AjaxJsonResponse(message + "", 500);
                    log("validate result info：" + message);
                    result = getDefaultResult(message, ajr, requestValidateFailureDefaultView);
                }
            }
        } catch (Throwable e) {
            if (isDevModel) {// 开发模式下打印异常
                session.setAttribute("ex", e);
                e.printStackTrace();
            }
            String message = e.getMessage();
            message = "请求异常" + (com.rybbaby.tss.core.utils.StringUtils.isAbsoluteNotNull(message) ? ("(" + message + ")") : "") + "!";
            boolean isRestController = this.controllerClass.isAnnotationPresent(RestController.class);
            boolean isResponseBodyController = this.controllerClass.isAnnotationPresent(ResponseBody.class);
            boolean isResponseBody = this.method.isAnnotationPresent(ResponseBody.class);
            if (isRestController || isResponseBodyController || isResponseBody) {
                AppResponse ajr = new AppResponse(message + "", 500);
                result = ajr.jsonResponse(false);
            } else {
                AjaxJsonResponse ajr = new AjaxJsonResponse(message + "", 500);
                log("validate result info：" + message);
                result = getDefaultResult(message, ajr, exceptionView);
            }
        }
        return result;
    }

    /**
     * 前置通知
     *
     * @param jp 连接点
     * @throws SecurityException
     * @throws NoSuchMethodException
     * @throws ClassNotFoundException
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     * @throws IllegalArgumentException
     */
    @Before(value = "requestPointcut()")
    public void doBefore(JoinPoint jp) throws NoSuchMethodException, SecurityException, ClassNotFoundException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
        String controllerName = controllerClass.getSimpleName();
        String logContent = null;
        if (requestLog != null) {
            logContent = requestLog.content();
        }
        log("request controller:" + controllerName);
        log("request method:" + signature);
        if (StringUtils.isNotEmpty(logContent)) {
            log("request method log:" + logContent);
        }
        if (requestParams != null && requestParams.length > 0) {
            log("request parameters:" + StringUtils.join(requestParams, ","));
        }
    }

    /**
     * 后置通知
     *
     * @param jp     连接点
     * @param result 返回值
     */
    @AfterReturning(value = "requestPointcut()", returning = "result")
    public void doAfter(JoinPoint jp, Object result) {
        String handlingResult;
        if (isProceed) {
            handlingResult = "request processing success ";
            log(handlingResult);
            //生成新的formkey和新的formToken
            HttpSession session = request.getSession();
            session.setAttribute(formKeyParamName, SequenceUtil.getOriginalUUID());
            session.setAttribute(formTokenParamName, SequenceUtil.getOriginalUUID());
        } else {
            handlingResult = "request a blocked, but the server refuse to process the request";
            log(handlingResult);
        }
        endTime = System.currentTimeMillis();
        log("response info：" + result);
        String duration = (endTime - startTime) + "ms";
        log("handling time:" + duration);
        if (isPersistenceRequestLog) {
            requestLogInfo.setResponseTime(new Timestamp(endTime));
            requestLogInfo.setResponseInfo(result != null ? result.toString() : null);
            requestLogInfo.setHandlingResult(handlingResult);
            requestLogInfo.setDuration(duration);
            persistenceRequestLog();
        }
        log("----------------------------  PROCESSING END   ------------------------------------ \n");
    }

    /**
     * 异常通知
     *
     * @param jp 连接点
     * @param e  异常对象
     */
    @AfterThrowing(value = "requestPointcut()", throwing = "e")
    public void doThrow(JoinPoint jp, Throwable e) {
        e.printStackTrace();
        String responseInfo = e.getMessage();
        logger.error(responseInfo, e);
        request.setAttribute("ex", e);
        String handlingResult = "request handling an exception occurs";
        log(handlingResult);
        endTime = System.currentTimeMillis();
        String duration = (endTime - startTime) + "ms";
        log("handling time:" + duration);
        if (isPersistenceRequestLog) {
            requestLogInfo.setResponseTime(new Timestamp(endTime));
            requestLogInfo.setResponseInfo(responseInfo);
            requestLogInfo.setHandlingResult(handlingResult);
            requestLogInfo.setDuration(duration);
        }
        persistenceRequestLog();
        log("---------------------------- PROCESSING END  ---------------------------------- \n");
    }

    /**
     * 持久化请求日志
     */
    private void persistenceRequestLog() {
        if (isPersistenceRequestLog && persistenceRequestLog != null) {
            log("持久化日志中...");
            ExecutorService cachedThread = Executors.newCachedThreadPool();
            cachedThread.execute(new Runnable() {

                @Override
                public void run() {
                    RequestLogBean shl = new RequestLogBean();
                    BeanUtils.copyProperties(requestLogInfo, shl);
                    shl.setRequestTime(new Timestamp(System.currentTimeMillis()));
                    Serializable id = persistenceRequestLog.persistenceLog(shl);
                    if (id == null) {
                        log("请求日志持久化失败!");
                    } else {
                        log("请求日志持久化成功!");
                    }
                }
            });
            cachedThread.shutdown();
        }
    }

    /**
     * 当本次请求不再被服务器继续处理时根据请求方法的返回值类型组装默认的响应的结果
     *
     * @param result 结果
     * @param ajr    ajax请求对象
     * @return
     */
    private Object getDefaultResult(Object result, AjaxJsonResponse ajr, String view) {
        if (method != null) {
            ResponseBody annotation = method.getAnnotation(ResponseBody.class);
            if (annotation != null) {// 返回结果直接写入HTTP response body中
                return ajr.jsonResponse(false);// 默认ajax请求在参数验证失败时都以json格式返回
            } else {// 返回视图页面
                Class<?> returnType = method.getReturnType();
                String returnTypeName = returnType.getSimpleName();
                if ("String".equals(returnTypeName)) {// 直接返回视图名
                    request.setAttribute("result", result);
                    return view;
                } else if ("ModelAndView".equals(returnTypeName)) {// 通过ModelAndView来响应
                    ModelAndView mav = new ModelAndView(view);
                    mav.addObject("result", result);
                    return mav;
                }
            }
        }
        return null;
    }

    /**
     * 通过切点初始化当切面的属性
     *
     * @param pjp 切点对象
     * @throws Exception
     */
    private void initAopField(ProceedingJoinPoint pjp) throws Exception {
        session = request.getSession();
        Object target = pjp.getTarget();
        controllerClass = target.getClass();
        requestParams = pjp.getArgs();
        signature = pjp.getSignature();
        method = getDisposeMethod(controllerClass, signature);
        requestLog = method.getAnnotation(RequestLog.class);
        isPersistenceRequestLog = false;
        if (requestLog != null) {
            isPersistenceRequestLog = requestLog.save();
        }
        token = method.getAnnotation(Token.class);
        isProceed = true;
        reqeustParameterFromatErrorInfo = null;
        reqeustParameterCustomValidateErrorInfo = null;
        session.removeAttribute("ex");
        if (isAutoValidateToken) {
            checkToken();
        }
        if (isAutoValidateParameter) {
            validatorParams();
        }
        // 初始化请求相关信息
        if (isPersistenceRequestLog) {
            BaseController baseController = new BaseController();
            baseController.setRequest(request);
            Object loginUserId = baseController.getLoginUserId();
            requestLogInfo.setAdminUserId(loginUserId == null ? null : loginUserId.toString());
            requestLogInfo.setRequestURI(request.getRequestURI());
            requestLogInfo.setClientIp(IPUtil.getRequestClientIp(request));
            requestLogInfo.setMethod(signature.toLongString());
            requestLogInfo.setControllerName(controllerClass.getSimpleName());
            if (requestLog != null) {
                String logContent = requestLog.content();
                if (StringUtils.isNotEmpty(logContent)) {
                    requestLogInfo.setLogContent(logContent);
                }
            }
            if (requestParams != null && requestParams.length > 0) {
                requestLogInfo.setParams(StringUtils.join(requestParams, ","));
            }
        }
    }

    /**
     * 获取token存储的前缀
     *
     * @return
     */
    public static String getTokenKey(HttpServletRequest request) {
        String formKey = request.getParameter(formKeyParamName);
        HttpSession session = request.getSession();
        if (StringUtils.isBlank(formKey)) {
            formKey = "form_" + SequenceUtil.getOriginalUUID();
            session.setAttribute("formKey", formKey);
        }
        return session.getId() + formKey + tokenSuffixName;
    }


    /**
     * 在当前会话创建新的Token
     *
     * @param newToken 新的Token
     */
    private void createToken(String newToken) {
        String tokenKey = getTokenKey(this.request);
        RedisClient.set(tokenKey, newToken);//保存token
        RedisClient.expire(tokenKey, 3 * 60);//设置Token的有效时长为3分钟
        log("create new tokken success ,token value:" + newToken);
    }

    /**
     * 验证Token,防止重复提交
     */
    private void checkToken() {
        if (token != null) {
            boolean validateToken = token.validateToken();
            if (validateToken) {
                String exceptionMsg = "该请求需要进行token验证的请求时，参数：'" + formKeyParamName + "'、'" + formTokenParamName + "'是必须的";
                String formKey = request.getParameter(formKeyParamName);
                if (StringUtils.isBlank(formKey)) {
                    throw new IllegalArgumentException(exceptionMsg);
                }
                String newToken = request.getParameter(formTokenParamName);
                if (StringUtils.isBlank(newToken)) {
                    throw new IllegalArgumentException(exceptionMsg);
                }
                String oldToken = RedisClient.get(getTokenKey(this.request));
                if (oldToken != null) {
                    if (oldToken.equals(newToken)) {
                        isProceed = false;
                        return;
                    }
                }
                createToken(newToken);
            }
            boolean validateSign = token.validateSign();
            if (validateSign) {
                boolean b = this.checkSign();
                if (!b) {
                    if (reqeustParameterFromatErrorInfo == null) {
                        reqeustParameterFromatErrorInfo = new StringBuffer();
                    }
                    reqeustParameterFromatErrorInfo.append("参数验签失败!");
                }
                isProceed = b;
            }
        }
    }

    /**
     * @return
     */
    public boolean checkSign() {
        HttpServletRequest request = this.request;
        //文件上传时重新处理request，必须在目标方法参数中包含一个MultipartHttpServletRequest类型参数
        if (ServletFileUpload.isMultipartContent(request)) {
            for (Object requestParam : requestParams) {
                if (requestParam instanceof MultipartHttpServletRequest) {
                    request = (MultipartHttpServletRequest) requestParam;
                    break;
                }
            }
        }
        String timestampStr = request.getParameter("timestamp");//参与生成签名的时间戳
        if (StringUtils.isNotBlank(timestampStr)) {
            long timestamp = Long.parseLong(timestampStr);
            String randomStr = request.getParameter("randomStr");//参与生成签名的随机字符串
            if (StringUtils.isNotBlank(randomStr)) {
                String clientSign = request.getParameter("sign");//客户端生成的签名
                if (StringUtils.isNotBlank(clientSign)) {
                    Enumeration<String> parameterNames = request.getParameterNames();
                    Map<String, Object> pramsMap = new HashMap<>();
                    //获取除了参与签名之外的其他参数
                    while (parameterNames.hasMoreElements()) {
                        String key = parameterNames.nextElement();
                        if (!key.equals("timestamp") && !key.equals("randomStr") && !key.equals("sign")) {
                            String value = request.getParameter(key);
                            pramsMap.put(key, value);
                        }
                    }
                    //验证签名
                    return SignUtil.validateSign(pramsMap, timestamp, randomStr, clientSign);
                } else {
                    throw new IllegalArgumentException("parameter 'sign' is required!");
                }
            } else {
                throw new IllegalArgumentException("parameter 'randomStr' is required!");
            }
        } else {
            throw new IllegalArgumentException("parameter 'timestamp' is required!");
        }
    }

    /**
     * 对传入参数进行合法验证
     *
     * @throws Exception
     */
    private void validatorParams() throws Exception {
        Parameter[] parameters = method.getParameters();
        Class<?>[] parameterTypes = method.getParameterTypes();
        int count = parameterTypes.length;
        AbstractVerifier targetVerifer = null;
        Parameter parameter = null;
        String parameterName = null;
        Annotation[] annotations = null, fieldAnnotations = null;
        Object paramValue = null;
        Class<?> paramClass = null;
        for (int j = 0; j < count; j++) {
            parameter = parameters[j];
            parameterName = parameter.getName();
            annotations = parameter.getAnnotations();
            paramClass = parameterTypes[j];
            if (!isJavaBaseType(paramClass)) {// 针对自定义pojo类参数类型进行验证
                Field[] fields = paramClass.getDeclaredFields();
                for (Field field : fields) {
                    fieldAnnotations = field.getAnnotations();
                    for (Annotation fieldAnnotation : fieldAnnotations) {
                        targetVerifer = AbstractVerifier.getTargetVerifer(fieldAnnotation);
                        if (targetVerifer != null) {
                            if (paramClass.isArray()) {
                                throw new Exception("Please do not use the pojo array as a parameter");
                            }
                            paramValue = requestParams[j];
                            field.setAccessible(true);
                            Object fieldValue = field.get(paramValue);
                            if (field.getType().isArray()) {
                                Object[] tempParamValue = decodeArray(fieldValue);
                                paramValue = tempParamValue;
                            } else {
                                paramValue = URLDecoder.decode(fieldValue + "", encoding);
                            }

                            Boolean result = targetVerifer.validate(paramValue);
                            if (!result) {
                                String fromatErrorInfo = parameterName + "." + field.getName() + "=" + paramValue;
                                appendErrorInfo(targetVerifer, fromatErrorInfo, fromatErrorInfo + ",");
                            }
                        }
                    }
                }
            } else {
                for (Annotation annotation : annotations) {
                    targetVerifer = AbstractVerifier.getTargetVerifer(annotation);
                    if (targetVerifer != null && targetVerifer instanceof AbstractVerifier) {
                        paramValue = requestParams[j];
                        boolean isArray = paramClass.isArray();
                        if (isArray) {
                            Object[] tempParamValue = decodeArray(paramValue);
                            paramValue = tempParamValue;
                        } else {
                            paramValue = URLDecoder.decode(paramValue + "", encoding);
                        }
                        Boolean result = targetVerifer.validate(paramValue);
                        if (!result) {
                            String errorParam = parameterName + "=" + (paramValue == null ? null : ((paramClass.isArray() ? Arrays.deepToString((Object[]) paramValue) : paramValue)));
                            appendErrorInfo(targetVerifer, errorParam, errorParam + ",");
                        }
                    }
                }
            }
        }
        if (reqeustParameterFromatErrorInfo != null || reqeustParameterCustomValidateErrorInfo != null) {
            isProceed = false;// 标识阻断本次请求
        }
    }

    /**
     * 对数组元素进行URL解码
     *
     * @param fieldValue 需要进行URL解码的数组
     * @return
     * @throws UnsupportedEncodingException
     */
    private Object[] decodeArray(Object fieldValue) throws UnsupportedEncodingException {
        Object[] tempParamValue = (Object[]) fieldValue;
        int length = tempParamValue.length;
        for (int i = 0; i < length; i++) {
            tempParamValue[i] = URLDecoder.decode(tempParamValue[i] + "", encoding);
        }
        return tempParamValue;
    }

    /**
     * 最佳验证错误信息
     *
     * @param targetVerifer   验证器对象
     * @param errorParam      参数名
     * @param fromatErrorInfo
     */
    private void appendErrorInfo(AbstractVerifier targetVerifer, String errorParam, String fromatErrorInfo) {
        String errorMsg = targetVerifer.getErrorMsg();
        if (StringUtils.isBlank(errorMsg)) {
            if (reqeustParameterFromatErrorInfo == null) {
                reqeustParameterFromatErrorInfo = new StringBuffer("以下参数格式错误:");
            }
            reqeustParameterFromatErrorInfo.append(fromatErrorInfo);
        } else {
            if (reqeustParameterCustomValidateErrorInfo == null) {
                reqeustParameterCustomValidateErrorInfo = new StringBuffer("以下参数未通过服务器端验证规则:");
            }
            reqeustParameterCustomValidateErrorInfo.append(errorParam + "(" + errorMsg + "),");
        }
    }

    /**
     * 判断指定的类是不是java基础类型
     *
     * @param clazz 需要判断的类型
     * @return
     */
    private boolean isJavaBaseType(Class<?> clazz) {
        if (clazz.isArray()) {
            return false;
        } else {
            if (org.springframework.util.ClassUtils.isPrimitiveOrWrapper(clazz)) {
                return true;
            }
            Package clazzPackage = clazz.getPackage();
            if (clazzPackage == null) {
                return true;
            }
            String name = clazzPackage.getName();
            if (name.equals("java.lang") || name.equals("java.math") || name.equals("java.util")) {
                return true;
            }
            return false;
        }
    }

    /**
     * 在当前会话创建新的Token
     */
    private void createToken() {
        removeToken();// 移除当前会话Token
        String tokenStr = SequenceUtil.getUpperCaseUUID();
        String formName = request.getParameter("formName");
        if (StringUtils.isEmpty(formName)) {
            formName = "";
        }
        session.setAttribute(formName + tokenSuffixName, tokenStr);
        log("create new tokken success ,token value:" + tokenStr);
    }

    /**
     * 移除当前会话中所有Token
     */
    private void removeToken() {
        Enumeration<?> attributeNames = session.getAttributeNames();
        while (attributeNames.hasMoreElements()) {
            String key = attributeNames.nextElement() + "";
            if (StringUtils.endsWith(key, tokenSuffixName)) {
                session.removeAttribute(key);
                log("delete tokken success ,token key:" + key);
            }
        }
    }

    /**
     * 获取请求方法对象
     *
     * @param cls       控制器对象
     * @param signature 连接点签名
     * @return
     * @throws ClassNotFoundException
     * @throws NoSuchMethodException
     */
    private Method getDisposeMethod(Class<? extends Object> cls, Signature signature) throws ClassNotFoundException, NoSuchMethodException {
        Method method = null;
        try {
            String longString = signature.toLongString();
            String paramsStr = StringUtils.substringBeforeLast(StringUtils.substringAfterLast(longString, "("), ")");
            if (StringUtils.isNotBlank(paramsStr)) {
                String[] paramsClass = StringUtils.split(paramsStr, ",");
                int paramCount = paramsClass.length;
                Class<?>[] parameterTypes = new Class<?>[paramCount];
                for (int i = 0; i < paramCount; i++) {
                    parameterTypes[i] = ClassUtils.getClass(paramsClass[i]);
                }
                if (paramCount != 0) {
                    method = cls.getDeclaredMethod(signature.getName(), parameterTypes);
                }
            }
            if (method == null) {
                method = cls.getDeclaredMethod(signature.getName());
            }
        } catch (Exception e) {
            Class<?> superclass = cls.getSuperclass();
            if (method == null && superclass != null) {
                method = getDisposeMethod(superclass, signature);
            } else if (method == null && superclass == null) {
                throw e;
            }
        }
        return method;
    }

    /**
     * 记录请求日志
     *
     * @param message 日志内容
     */
    private void log(String message) {
        if (isShowlog) {
            this.logger.info(message);
        }
    }

    public void setPersistenceRequestLog(IPersistenceRequestLog persistenceRequestLog) {
        this.persistenceRequestLog = persistenceRequestLog;
    }

}
